package com.crl.rcdp.gateway.filter;

import com.cars.util.jwt.JwtUtil;
import com.crl.rcdp.gateway.util.IPUtil;
import com.crl.rcdp.sys.model.SysErrorLog;
import com.crl.rcdp.sys.service.SysErrorLogService;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @description:
 * @author: 孔垂云
 * @version: 1.0
 * @date: 2020/7/13 0:20
 */
public class ExceptionLogFilter implements GlobalFilter, Ordered {
    @Autowired
    private SysErrorLogService sysErrorLogService;


    //    @Override
    public Mono<Void> filter2(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("记录异常日志"); //TODO 异常日志写库
        //请求过慢或返回值非00200
        //调用请求之前统计时间
        Long startTime = System.currentTimeMillis();
        return chain.filter(exchange).then().then(Mono.fromRunnable(() -> {
            //调用请求之后统计时间
            Long endTime = System.currentTimeMillis();
            long consume = endTime - startTime;
            if (consume > 10) { //请求超过三秒
                //写入数据库 TODO
                //获取请求参数
                String body = resolveBodyFromRequest(exchange.getRequest());
                this.addErrorLog(exchange, body);
            }
        }));
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        //释放掉内存
                        DataBufferUtils.release(dataBuffer);
                        String s = new String(content, Charset.forName("UTF-8"));
                        //TODO，s就是response的值，想修改、查看就随意而为了
                        System.out.println("返回值：" + s);
                        addErrorLog(exchange, s);
                        byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    /**
     * 获取请求体中的字符串内容
     *
     * @param serverHttpRequest
     * @return
     */
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        StringBuilder sb = new StringBuilder();

        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            DataBufferUtils.release(buffer);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
        });
        return sb.toString();

    }

    /**
     * 往数据库增加请求日志，后续可以改为写文本日志或记录到ELK
     */
    private void addErrorLog(ServerWebExchange exchange, String body) {
        System.out.println("记录异常日志"); //TODO
        ServerHttpRequest servletRequest = exchange.getRequest();
        //判断是否需要校验权限
        String servletPath = servletRequest.getPath().toString();//获取请求url
        String authorization = servletRequest.getHeaders().getFirst("Authorization");//获取authorization
        String appid = servletRequest.getHeaders().getFirst("appid");//appid
        String accessToken = servletRequest.getHeaders().getFirst("accessToken");//accessToken
        SysErrorLog sysErrorLog = new SysErrorLog();
        sysErrorLog.setOwner(JwtUtil.getJWTOwner(accessToken));
        sysErrorLog.setClientIp(IPUtil.getIpAddress(exchange.getRequest()));//ip地址
        sysErrorLog.setAuthType(FilterUtil.getAuthType(authorization, accessToken, appid));//授权方式
        sysErrorLog.setPath(servletPath);//请求地址
        //servicename
        System.out.println(exchange.getAttributes().toString());
        sysErrorLog.setServiceName(exchange.getAttribute("SERVICE_NAME"));
        sysErrorLog.setParams(body.getBytes());//请求参数
        sysErrorLog.setOwner(FilterUtil.getOwner(authorization, accessToken, appid));//owner
        sysErrorLogService.add(sysErrorLog);
    }

    @Override
    public int getOrder() {
        return -3;
    }
}
